<?php
/**
 * Created by PhpStorm.
 * User: Rain
 * Date: 2020/5/20
 * Time: 10:10
 */

namespace app\admin\service\business\Alone\Access;


use app\admin\service\BaseService;
use app\admin\service\business\Alone\Access\Models\MixedModel;
use think\helper\Str;

/**
 * Class AccessService
 *
 * @property-read MixedModel $mixed
 *
 * @package app\admin\service\business\Alone\Access
 */
class AccessService extends BaseService
{
    protected $rely = [
        'mixed' => MixedModel::class,
    ];

    // 无限标识
    private $slug = '*';

    // 当前用户下的角色
    public $roles;

    /**
     * 判断是否为管理员
     *
     * @return bool
     */
    public function isAdmin(): bool
    {
        return 1 == $this->data['user']->id;
    }

    /**
     * 检查权限
     *
     * @return bool
     */
    public function boot()
    {
        // 判断是否为超级管理员
        if ($this->isAdmin()) return true;

        // 当前管理员下的角色
        if (!$this->roles = $this->getRoles()) return false;

        // 路由 前缀
        $prefix = app('http')->getName() . '-';

        // 返回权限
        return $this->check($prefix);
    }

    /**
     * 检查权限
     *
     * @param string $prefix
     * @return bool
     */
    private function check(string $prefix): bool
    {
        // 初始化变量
        list($roles, $routeName, $routeRule) = [
            $this->roles,
            $prefix . request()->rule()->getName(),
            $prefix . request()->rule()->getRule(),
        ];

        // 用户下的所有角色
        foreach ($roles as $k => $role) {
            // 当前角色是否有权限
            if ($role->rules->isEmpty()) continue;

            // 角色下的所有权限
            foreach ($role->rules as $rule) {
                // 验证是否为当前请求
                if (!$this->isMethod($rule)) continue;

                // 路由验证
                $routes = explode("\n", $rule->routes);

                // 路由验证
                foreach ($routes as $route) {
                    // 验证路由名称 name
                    if ($this->verifyRule($prefix, $route, $routeName)) return true;

                    // 验证路由uri
                    if ($this->verifyRule($prefix, $route, $routeRule)) return true;
                }
            }
        }

        return false;
    }

    /**
     * 验证规则
     *
     * @param string $prefix 路由前缀
     * @param string $route 已有路由规则
     * @param string $hasRoute 检查的路由
     * @return bool
     */
    private function verifyRule(string $prefix, string $route, string $hasRoute): bool
    {
        // 添加前缀，防止破解
        $newRoute = $prefix . $route;

        // 后缀是否为 *
        if (Str::endsWith($route, $this->slug)) {
            // 获取路由 除去*
            $newRoute = explode('*', $newRoute)[0];

            // 判断含有此路由
            if (Str::contains($hasRoute, $newRoute)) return true;
        } else {
            // 判断路由是否相等
            if ($newRoute === $hasRoute) return true;
        }

        return false;
    }

    /**
     * 获取当前用户下角色列表
     *
     * @return bool|object
     */
    private function getRoles()
    {
        $roles = $this->mixed->getRoleList($this->data['user']);

        return $roles->isEmpty() ? false : $roles;
    }

    /**
     * 允许的类型请求
     *
     * @param $rule
     * @return bool
     */
    private function isMethod($rule)
    {
        // 解析请求信息
        $methods = explode('|', $rule->method);

        // 允许所有类型请求
        if (in_array('ANY', $methods)) return true;

        return in_array(request()->method(), $methods);
    }
}
